package com.tamir.template.util;

import com.tamir.template.bean.IntermediateOperator;
import com.tamir.template.bean.LogicOperate;
import com.tamir.template.config.OperatorConfig;
import com.tamir.template.exception.TemplateException;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.util.ListIterator;
import java.util.Stack;

/**
 * @author : tanggh
 * @description :逻辑操作解析公共类
 * @date : 2017/1/4
 */
public class LogicOperateUtil
{
    private static Logger logger = Logger.getLogger(LogicOperateUtil.class);

    /**
     * 从中间逻辑操作栈生成LogicOperate
     * @param stacks
     * @return
     */
    public static LogicOperate parseLogicOpeFromIntermediateOperator(Stack<IntermediateOperator> stacks){
        LogicOperate rootOperate = null;
        if(stacks != null && !stacks.isEmpty()){
            rootOperate = new LogicOperate();
            Stack<Object> valueStack = new Stack<Object>();
            IntermediateOperator[] operatorsArray = new IntermediateOperator[0];
            operatorsArray = stacks.toArray(operatorsArray);
            int len = operatorsArray.length;
            IntermediateOperator inOp = null;
            for (int i=0; i<len; i++){
                inOp = operatorsArray[i];
                OperaterUtil.genLogicOperator(inOp, valueStack);
            }
            rootOperate = (LogicOperate) valueStack.pop();
        }
        return rootOperate;
    }

    /**
     * 解析表达式
     * @param express
     * @return LogicOperate
     */
    public static LogicOperate parseExpress(String express){
        if(StringUtil.isEmpty(express)){
            return null;
        }
        express = express.replaceAll("\\s*", "");
        int len = express.length();

        //中间操作表达式(逆波兰表达式堆栈)
        Stack<IntermediateOperator> intermediateOperatorStack = new Stack<IntermediateOperator>();
        //操作符堆栈
        Stack<String> operatorStack = new Stack<String>();
//        Stack<LogicOperate> logicOperateStack = new Stack<LogicOperate>();
        int expressStartIndex = 0;
        int expressEndIndex = 0;
        char cha = 0;
        String chaStr = null;
        boolean isOperator = false;
        LogicOperate root = null;

        LogicOperate lastOperator = null;
        String ex = null;
        int next = 0;
        String op = null;
        String lastOp = null;
        for (int i=0; i<len; i++){
            cha = express.charAt(i);
            chaStr = String.valueOf(cha);
            expressEndIndex = i;
            if(OperatorConfig.symbolStr.contains(chaStr)){
                if(cha == OperatorConfig.leftBracket){
                    operatorStack.push(chaStr);
                    expressStartIndex = i+1;
                }else if(cha == OperatorConfig.rightBracket){
                    if(operatorStack.isEmpty()){
                        throw new TemplateException("", "语法错误在附近"+express.substring(expressEndIndex,
                                express.length()));
                    }
//                    lastOperator = logicOperateStack.peek();
                    ex = express.substring(expressStartIndex, expressEndIndex);
                    if(!StringUtil.isEmpty(ex)){
                        intermediateOperatorStack.push(new IntermediateOperator(ex, false));
                    }
                    lastOp = operatorStack.peek();
                    while (OperatorConfig.leftBracket != lastOp.charAt(0)){
                        operatorStack.pop();
                        intermediateOperatorStack.add(new IntermediateOperator(lastOp, true));
                        if(!operatorStack.isEmpty()){
                            lastOp = operatorStack.peek();
                        }else{
                            throw new TemplateException("", ")不匹配");
                        }
                    }
                    //删除左括号
                    operatorStack.pop();
                    expressStartIndex = i+1;
                }else{
                    if(expressStartIndex > expressEndIndex){
                        throw new TemplateException("", "语法错误在"+express.substring(expressEndIndex,
                                express.length()) +"附近");
                    }

                    next = i + 1;
                    if(next < len){
                        op = OperaterUtil.judgeOperator(cha, express.charAt(next));
                    }else{
                        throw new TemplateException("", "can not end with operator:"+ cha);
                    }
                    ex = express.substring
                            (expressStartIndex, expressEndIndex);
                    if(!StringUtil.isEmpty(ex)){
                        intermediateOperatorStack.push(new IntermediateOperator(ex, false));
                    }
                    lastOp = operatorStack.isEmpty() ? null : operatorStack.peek();
                    if(lastOp != null && lastOp.charAt(0) != OperatorConfig.leftBracket  &&
                            OperatorConfig
                            .getInstance().getOperatorLevelByOp(op) <=
                            OperatorConfig
                                    .getInstance().getOperatorLevelByOp(lastOp)){
                        intermediateOperatorStack.push(new IntermediateOperator(lastOp, true));
                        operatorStack.pop();
                    }
                    operatorStack.push(op);
                    if(op.length() >= 2){
                        i = i + 1;
                    }
                    expressStartIndex = i+1;
                }

            }
        }
        if(expressEndIndex < len && expressStartIndex <= expressEndIndex){
            ex = express.substring(expressStartIndex, len);
            if(!StringUtil.isEmpty(ex)){
                intermediateOperatorStack.push(new IntermediateOperator(ex, false));
            }
        }

        if(!operatorStack.isEmpty()){
            String oddOperator = null;
            while(!operatorStack.isEmpty()){
                oddOperator = operatorStack.peek();
                intermediateOperatorStack.push(new IntermediateOperator(oddOperator, true));
                operatorStack.pop();
            }
        }
        ListIterator<IntermediateOperator> inOpItor = intermediateOperatorStack.listIterator();
        IntermediateOperator tmp = null;
        while (inOpItor.hasNext()){
            tmp = inOpItor.next();
            logger.debug(tmp.getExpress());
        }
        LogicOperate rootLogicOperator = LogicOperateUtil.parseLogicOpeFromIntermediateOperator
                (intermediateOperatorStack);
        if(rootLogicOperator == null){
            throw new TemplateException("", "Parse LogicOperate fail from express");
        }
        return rootLogicOperator;
    }

    /**
     * 根据表达式获取入参关键字
     * @param express
     * @return
     */
    public static String getInputKey(String express){
        if(!StringUtil.isEmpty(express)){
            String keyAndValue = express.replaceAll("\\s+", "");
            String[] valueArray = keyAndValue.split("\\.");
            if (valueArray.length > 0)
            {
                String key = valueArray[0];
                //map类型
                if (key.indexOf("['") != -1)
                {
                    String[] keys = key.split("\\['");
                    if (keys.length > 1)
                    {
                        key = keys[0].replaceAll("\\['", "");
                    }
                }
                else
                {
                    //数组类型
                    String[] keys = key.split("\\[");
                    if (keys.length > 1)
                    {
                        key = keys[0].replaceAll("\\[", "");
                    }
                }
                //只有表达式才有输入key
                return StringUtil.isNumeric(key)?null:key;
            }
        }
        return null;
    }

    /**
     * 获取值
     * @param operate   逻辑操作对象
     * @return
     */
    public static Object getValue(LogicOperate operate)
    {
        Object retVal = null;
        if(operate != null){
            Object leftObj = null;
            Object rightObj = null;
            if(operate.getOperator() != null){
                leftObj = getValue(operate.getLeftOperate());
                rightObj = getValue(operate.getRightOperate());
                retVal = OperaterUtil.calObject(operate.getOperator(), leftObj, rightObj, null,
                        operate);
            }else{
                String ex = operate.getExpress();
                if(StringUtil.isBoolean(ex)){
                    retVal = new Boolean(ex);
                }else if(StringUtil.isNumeric(ex)){
                    retVal = new BigDecimal(operate.getExpress());
                }
            }
            if(operate.isNon()){
                if(retVal instanceof Boolean){
                    retVal = !(Boolean)retVal;
                }else{
                    retVal = !StringUtil.string2Boolean(retVal.toString());
                }
            }
        }
        return retVal;
    }

    public static void main(String[] args)
    {
        String express = "1+2>=1+1";
        LogicOperate rootLogicOperate = LogicOperateUtil.parseExpress(express);
        System.out.println(LogicOperateUtil.getValue(rootLogicOperate));
    }

}
